{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "41e58894-879d-4da8-8f6f-3472fe806f4b",
   "metadata": {},
   "source": [
    "在前面的例子中, 我们从依赖项 (\"可依赖对象\") 中返回了一个 dict:\n",
    "\n",
    "但是后面我们在路径操作函数的参数 commons 中得到了一个 dict。\r\n",
    "\r\n",
    "我们知道编辑器不能为 dict 提供很多支持(比如补全)，因为编辑器不知道 dict 的键和值类型。\r\n",
    "\r\n",
    "对此，我们可以做的更好..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "98e9d520-18e1-4db5-b42b-a7bd667b971f",
   "metadata": {},
   "source": [
    "到目前为止，您看到的依赖项都被声明为函数。\r\n",
    "\r\n",
    "但这并不是声明依赖项的唯一方法(尽管它可能是更常见的方法)。\r\n",
    "\r\n",
    "关键因素是依赖项应该是 \"可调用\n",
    "\n",
    "Python 中的 \"可调用对象\" 是指任何 Python 可以像函数一样 \"调用\" 的对象。\r\n",
    "\r\n",
    "所以，如果你有一个对象 something (可能不是一个函数)，你可以 \"调用\" 它(执行它)，就\n",
    "\n",
    "something()\n",
    "\n",
    "或者\n",
    "\n",
    "something(some_argument, some_keyword_argument=\"foo\")\n",
    "\n",
    "这就是 \"可调用对象\"。像：对象\"。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9f24a908-a2dc-4072-83cc-97e6c0d5bdce",
   "metadata": {},
   "source": [
    "您可能会注意到，要创建一个 Python 类的实例，您可以使用相同的语法。\r\n",
    "\r\n",
    "举个例子:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "be58e463-8d3a-46cb-a943-a50ecbf75288",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Cat:\n",
    "    def __init__(self, name: str):\n",
    "        self.name = name\n",
    "\n",
    "\n",
    "fluffy = Cat(name=\"Mr Fluffy\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce398005-8c6d-47f6-b8a6-57badea52746",
   "metadata": {},
   "source": [
    "在这个例子中, fluffy 是一个 Cat 类的实例。\r\n",
    "\r\n",
    "为了创建 fluffy，你调用了 Cat 。\r\n",
    "\r\n",
    "所以，Python 类也是 可调用对象。\r\n",
    "\r\n",
    "因此，在 FastAPI 中，你可以使用一个 Python 类作为一个依赖项。\r\n",
    "\r\n",
    "实际上 FastAPI 检查的是它是一个 \"可调用对象\"（函数，类或其他任何类型）以及定义的参数。\r\n",
    "\r\n",
    "如果您在 FastAPI 中传递一个 \"可调用对象\" 作为依赖项，它将分析该 \"可调用对象\" 的参数，并以处理路径操作函数的参数的方式来处理它们。包括子依赖项。\r\n",
    "\r\n",
    "这也适用于完全没有参数的可调用对象。这与不带参数的路径操作函数一样。\r\n",
    "\r\n",
    "所以，我们可以将上面的依赖项 \"可依赖对象\" common_parameters 更改为类 Comm\n",
    "\n",
    "注意用于创建类实例的 __init__ 方法：\n",
    "\n",
    "它与我们以前的 common_parameters 具有相同的参数：\n",
    "\n",
    "这些参数就是 FastAPI 用来 \"处理\" 依赖项的。\r\n",
    "\r\n",
    "在两个例子下，都有：\r\n",
    "\r\n",
    "一个可选的 q 查询参数，是 str 类型。\r\n",
    "一个 skip 查询参数，是 int 类型，默认值为 0。\r\n",
    "一个 limit 查询参数，是 int 类型，默认值为 100。\r\n",
    "在两个例子下，数据都将被转换、验证、在 OpenAPI schema 上文档化，等等。onQueryParams:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "66be3559-6802-4cf5-8720-c4d86ac21797",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:     Started server process [22084]\n",
      "INFO:     Waiting for application startup.\n",
      "INFO:     Application startup complete.\n",
      "INFO:     Uvicorn running on http://0.0.0.0:8009 (Press CTRL+C to quit)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:     127.0.0.1:65386 - \"GET /users/?q=%E6%9D%8E%E5%9B%9B HTTP/1.1\" 200 OK\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO:     Shutting down\n",
      "INFO:     Waiting for application shutdown.\n",
      "INFO:     Application shutdown complete.\n",
      "INFO:     Finished server process [22084]\n"
     ]
    }
   ],
   "source": [
    "import uvicorn\n",
    "from fastapi import Depends, FastAPI\n",
    "app = FastAPI()\n",
    "\n",
    "class CommonQueryParams:\n",
    "    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):\n",
    "        self.q = q\n",
    "        self.skip = skip\n",
    "        self.limit = limit\n",
    "\n",
    "\n",
    "@app.get(\"/items/\")\n",
    "async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):\n",
    "    return commons\n",
    "\n",
    "\n",
    "@app.get(\"/users/\")\n",
    "async def read_users(commons: CommonQueryParams = Depends(CommonQueryParams)):\n",
    "    return commons\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    config = uvicorn.Config(app, host='0.0.0.0', port=8009)\n",
    "    server = uvicorn.Server(config)\n",
    "    await server.serve()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2ad3e075-994a-4714-a8af-62862f81c2eb",
   "metadata": {},
   "source": [
    "FastAPI 调用 CommonQueryParams 类。\n",
    "\n",
    "这将创建该类的一个 \"实例\"，该实例将作为参数 commons 被传递给你的函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a72838f0-c384-4bf0-a36e-f1a82c89a157",
   "metadata": {},
   "outputs": [],
   "source": [
    "url = 'http://127.0.0.1:8009/items/?q=张三' \n",
    "res = requests.get(url) \n",
    "res.text\n",
    "\n",
    "# 在另一个ipynb文件中运行代码，会得到 '{\"q\":\"张三\",\"skip\":0,\"limit\":100}'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "228333d4-1cbf-44d7-a704-4bfbdde4321d",
   "metadata": {},
   "outputs": [],
   "source": [
    "url = 'http://127.0.0.1:8009/users/?q=李四' \n",
    "res = requests.get(url) \n",
    "res.text\n",
    "\n",
    "# 在另一个ipynb文件中运行代码，会得到 '{\"q\":\"李四\",\"skip\":0,\"limit\":100}'"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c8a6f9f0-414a-40c6-a8c9-40a0c414c0ec",
   "metadata": {},
   "source": [
    "## 类型注解 vs Depends"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "797099c3-fc73-4754-a668-53fea3dfc87e",
   "metadata": {},
   "source": [
    "注意，我们在上面的代码中编写了两次CommonQueryParams：\n",
    "\n",
    "commons: CommonQueryParams = Depends(CommonQueryParams)\n",
    "\n",
    "你可以简写成：\n",
    "commons = Depends(CommonQueryParams)\n",
    "或者\n",
    "commons: CommonQueryParams = Depends()\n",
    "\n",
    "但是更推荐写成 commons: CommonQueryParams = Depends()\n",
    "因为，声明类型是被鼓励的，因为那样你的编辑器就会知道将传递什么作为参数 commons ，然后它可以帮助你完成代码，类型检查，等等。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
